﻿using LunarSF.SHomeWorkshop.LunarMarkdownEditor.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace LunarSF.SHomeWorkshop.LunarMarkdownEditor
{
    class AutoCreateLinksToTitles
    {
        /// <summary>
        /// 自动为 正文 中包含的、与某个 Markdown 文件的标题文本相同的片段加上“&lt;: :&gt;”标记。
        /// 这样就可以利用 &lt;:xxx:&gt; 的自动尝试创建链接的功能。
        /// </summary>
        /// <param name="srcText"></param>
        /// <returns></returns>
        public static string Execute(string srcText, string srcFilePath)
        {
            PrepareWords();

            var lines = srcText.Split(new string[] { "\r\n", }, StringSplitOptions.None);

            StringBuilder sb = new StringBuilder();

            foreach (var line in lines)
            {
                if (string.IsNullOrWhiteSpace(line)) continue;
                if (line.StartsWith("    ") || line.StartsWith("\t") ||
                    line.StartsWith("!") || line.StartsWith("！") ||
                    line.StartsWith(";") || line.StartsWith("；") ||
                    line.StartsWith("%") || line.StartsWith("@") ||
                    line.StartsWith("#"))  // 实践证明，六级标题中支持这个简直是自找麻烦。
                {
                    sb.Append(line);
                    sb.Append("\r\n");
                    continue;  // 注释行中忽略。
                }

                List<TextPiece> pieces = Text.SplitToPiecesByRegex(@"(</{0,1}[a-zA-Z][a-zA-Z0-9_]{0,}( {1,}.*)?>)|(\[.{1,}?\]\(.{0,}?\))|(`.{1,}?`)|(《.{1,}》)|([<]:.{1,}:[>])", line);
                StringBuilder sb2 = new StringBuilder();

                foreach (var piece in pieces)
                {
                    var pieceAreas = new List<IndexArea>();
                    if (piece.IsMartchText)
                    {
                        sb2.Append(piece.SourceText);
                        continue;
                    }

                    MarkIndexAreas(piece, ref pieceAreas);
                    pieceAreas.Sort(new IndexAreaComparer());
                    var result = piece.SourceText;
                    for (int i = pieceAreas.Count - 1; i >= 0; i--)
                    {
                        var pa = pieceAreas[i];
                        if (pa.KeyWordItem.FullPath.ToLower() == srcFilePath.ToLower() ||
                            (pa.KeyWordItem.FullPath + "_" + pa.KeyWordItem.ShortName + ".md").ToLower() == srcFilePath.ToLower()) continue;  // 不应创建到自身的链接。
                        result = result.Substring(0, pa.Start) +
                            "<a href=\"" + MarkdownEditorBase.GetRelativePath(srcFilePath,
                            (pa.KeyWordItem.ItemType == WorkspaceTreeViewItem.Type.File ? pa.KeyWordItem.FullPath : pa.KeyWordItem.FullPath + "_" + pa.KeyWordItem.ShortName + ".md"), true) + "\">" + pa.KeyWordItem.Title + "</a>" +
                            result.Substring(pa.Start + pa.KeyWordItem.Title.Length);
                    }
                    piece.ReplacedText = result;
                    sb2.Append(result);
                }

                sb.Append(sb2);
                sb.Append("\r\n");
            }

            return sb.ToString();
        }

        private static List<WorkspaceTreeViewItem> keyWordItems = new List<WorkspaceTreeViewItem>();

        private static void PrepareWords()
        {
            keyWordItems.Clear();

            if (Globals.MainWindow.tvWorkDirectory == null || Globals.MainWindow.tvWorkDirectory.Items.Count <= 0) return;

            var treeView = Globals.MainWindow.tvWorkDirectory;
            var item = treeView.Items[0] as WorkspaceTreeViewItem;
            ReadWorkspaceTreeViewItems(ref item);

            keyWordItems.Sort(new KeyWordItemComparer());
        }

        private static void ReadWorkspaceTreeViewItems(ref WorkspaceTreeViewItem wi)
        {
            if (wi.StatuHeader == "[#]") return;

            var curItem = new WorkspaceTreeViewItem(wi.Title, wi.FullPath, wi.StatuHeader, wi.StatuTail, wi.ToolTip as string, wi.IsHomePage, wi.ItemType, wi.ChmImageIndex, wi.IsChecked, wi.MasterWindow);
            foreach (var subItem in wi.Items)
            {
                var subI = subItem as WorkspaceTreeViewItem;
                if (subI == null) continue;
                switch (subI.ItemType)
                {
                    case WorkspaceTreeViewItem.Type.File:
                        //case WorkspaceTreeViewItem.Type.Image:  // 图像是不能直接链接的，否则会破坏页面布局。
                        {
                            var newSubI = new WorkspaceTreeViewItem(subI.Title, subI.FullPath, subI.StatuHeader, subI.StatuTail,
                                subI.ToolTip as string, subI.IsHomePage, subI.ItemType, subI.ChmImageIndex, subI.IsChecked, subI.MasterWindow);
                            if (Globals.MainWindow.IgnoreAutoLinkTitles.Contains(newSubI.Title) == false)
                                keyWordItems.Add(newSubI);
                            break;
                        }
                    case WorkspaceTreeViewItem.Type.Folder:
                        {
                            var newSubI = new WorkspaceTreeViewItem(subI.Title, subI.FullPath, subI.StatuHeader, subI.StatuTail,
                                subI.ToolTip as string, subI.IsHomePage, subI.ItemType, subI.ChmImageIndex, subI.IsChecked, subI.MasterWindow);
                            if (Globals.MainWindow.IgnoreAutoLinkTitles.Contains(newSubI.Title) == false)
                                keyWordItems.Add(newSubI);
                            ReadWorkspaceTreeViewItems(ref subI);
                            break;
                        }
                    default: continue;
                }
            }

            // 为什么要允许用户忽略对某些标题的自动链接？因为可能出现不同层级、但标题文本一样的情况。
            // 以 ~ 结尾的是资源目录，没有必要创建自动链接。
            if (Globals.MainWindow.IgnoreAutoLinkTitles.Contains(curItem.Title) == false && curItem.Title.EndsWith("~") == false)
                keyWordItems.Add(curItem);
        }

        private static void MarkIndexAreas(TextPiece piece, ref List<IndexArea> pieceAreas)
        {
            for (int i = keyWordItems.Count - 1; i >= 0; i--)
            {
                // 采用标记索引起、止区间的方法。
                var keyWorkItem = keyWordItems[i];

                GetIndexAreas(ref pieceAreas, piece, keyWorkItem);
            }
        }

        private static bool IsMarkedArea(ref List<IndexArea> pieceAreas, IndexArea pa)
        {
            if (pieceAreas == null || pieceAreas.Count <= 0) return false;

            foreach (var ma in pieceAreas)
            {
                var paStart = pa.Start;
                var paEnd = pa.Start + pa.KeyWordItem.Title.Length;
                var maStart = ma.Start;
                var maEnd = ma.Start + ma.KeyWordItem.Title.Length;

                if ((paStart >= ma.Start && paEnd <= maEnd) ||
                    (paEnd >= ma.Start && paEnd <= maEnd) ||
                    (maStart >= paStart && maStart <= paEnd) ||
                    (maEnd >= paStart && maEnd <= paEnd))
                {
                    // 说明两者有交叉
                    return true;
                }
            }

            return false;
        }

        private static List<IndexArea> GetIndexAreas(ref List<IndexArea> pieceAreas, TextPiece piece, WorkspaceTreeViewItem keyWordItem)
        {
            var index = piece.SourceText.IndexOf(keyWordItem.Title);
            while (index >= 0)
            {
                var newIndexArea = new IndexArea() { Start = index, KeyWordItem = keyWordItem, };
                if (IsMarkedArea(ref pieceAreas, newIndexArea) == false)
                {
                    pieceAreas.Add(newIndexArea);
                }
                index = piece.SourceText.IndexOf(keyWordItem.Title, index + keyWordItem.Title.Length);
            }

            return pieceAreas;
        }
    }

    public class IndexArea
    {
        public int Start { get; set; }
        public WorkspaceTreeViewItem KeyWordItem { get; set; }
    }

    public class IndexAreaComparer : IComparer<IndexArea>
    {
        public int Compare(IndexArea x, IndexArea y)
        {
            if (x == null && y == null) return 0;
            if (x == null) return -1;
            if (y == null) return 1;

            if (x.Start > y.Start) return 1;
            if (x.Start < y.Start) return -1;
            return 0;
        }
    }

    public class KeyWordItemComparer : IComparer<WorkspaceTreeViewItem>
    {
        public int Compare(WorkspaceTreeViewItem x, WorkspaceTreeViewItem y)
        {
            if (x == null && y == null) return 0;
            if (x == null) return -1;
            if (y == null) return 1;

            if (x.Title.Length > y.Title.Length) return 1;
            if (x.Title.Length < y.Title.Length) return -1;

            return x.Title.CompareTo(y.Title);  // 等长的才有必要比较字符序列
        }
    }
}
